/*
 * @Author:
 * @Date: 2024-08-26 17:11:28
 * @LastEditor: zhuxiaoyi
 * @LastEditTime: 2024-09-20 18:36:00
 * @Description:
 */
import { Provide, App, Inject, Config } from '@midwayjs/core';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository, Like } from 'typeorm';
import { SimulationTask } from '../entity/simulationTask.entity';
import { CreateTaskDto, uploadDto } from '../dto/SimulationTaskDto';
import { Algorithm } from '../entity/algorithm.entity';
import { GraphService } from './graph.service';
import axios from 'axios';
import { Validate } from '@midwayjs/validate';
import * as fs from 'fs';
import { promises as fs1 } from 'fs';
import * as path from 'path';
import { TaskService } from './task.service';
const { v4: uuidv4 } = require('uuid');

@Provide()
export class SimulationTaskService {
    @InjectEntityModel(SimulationTask)
    simulationTaskModel: Repository<SimulationTask>;

    @InjectEntityModel(Algorithm)
    AlgorithmModel: Repository<Algorithm>;

    @Inject()
    taskService: TaskService;

    @Inject()
    graphService: GraphService;

    //算法任务执行
    @Validate()
    async createSimulationTask(params: CreateTaskDto) {
        try {
            const uploadDir = `D:/01北京城市内涝模型/4_工程目录/${this.formatDate(new Date().getTime())}`; // 目标目录
            // 检查文件夹是否存在
            if (!fs.existsSync(uploadDir)) {
                // 创建文件夹
                fs.mkdirSync(uploadDir, { recursive: true });
            }
            const filename = 'input_' + new Date().getTime() + '.json'; //从上传信息中获取文件名
            const uploadPath = path.join(uploadDir, filename); //拼接完整路径
            // 保存文件
            await fs1.writeFile(uploadPath, JSON.stringify(params));
            const algorithm = await this.AlgorithmModel.findOne({
                where: { id: 135 },
            });

            if (!algorithm) {
                return {
                    success: false,
                    message: '未找到要执行的算法',
                };
            }
            const parsedParameters = JSON.parse(algorithm.parameters);
            let outputFile, taskId;
            parsedParameters.forEach(param => {
                const key = param.param_name;
                if (key == 'TaskID') {
                    param.default_value = params.taskId;
                    taskId = params.taskId
                }
                if (key == 'inputFile') {
                    param.default_value = uploadPath;
                }
                if (key == 'outputFile') {
                    outputFile = path.join(
                        uploadDir,
                        'output_' + new Date().getTime() + '.json'
                    );
                    param.default_value = outputFile;
                }
            });
            algorithm.parameters = JSON.stringify(parsedParameters);
            const task = await this.taskService.createTask(algorithm);

            return {
                success: true,
                data: {
                    id: task.id,
                    taskId: params.taskId,
                },
                message: '任务创建成功',
            };
        } catch (error) {
            console.error('创建任务失败:', error.message.cause);
            return {
                success: false,
                message: '参数验证失败或创建任务失败',
                error: error.message.cause,
            };
        }
    }

    async createQuanguoSimulationTask(params: CreateTaskDto) {
        const taskId = params.taskId;
        const targetDir = path.join("D:/02ChinaModel/02Project", taskId, "01_origin");
        const targetFile = path.join(targetDir, "input_China.json");

        try {
            // 检查目标目录是否存在，如果不存在则创建
            if (!fs.existsSync(targetDir)) {
                fs.mkdirSync(targetDir, { recursive: true });
            }

            // 将 params 写入 JSON 文件，排除 taskId 本身
            fs.writeFileSync(targetFile, JSON.stringify(params), 'utf-8');
            console.log(`JSON 文件已成功保存到 ${targetFile}`);
            this.graphService.executeGraphByDynamic4(80, taskId)
            let result = {
                success: true,
                taskId: params.taskId,
                message: '推送成功',
            };
            return result;
        } catch (error) {
            console.error("保存 JSON 文件过程中出错:", error);
            let result = {
                success: false,
                taskId: params.taskId,
                message: error,
            };
            return result;
        }
    }



    formatDate(timestamp) {
        const date = new Date(timestamp);
        const year = date.getFullYear();
        const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始
        const day = String(date.getDate()).padStart(2, '0');
        return `${year}${month}${day}`;
    }

    @Validate()
    async uploadFile(params: uploadDto, file: any) {
        try {
            let result = {
                success: true,
                taskId: params.taskId,
                message: '上传成功',
            };
            if (!file || !file.data) {
                throw new Error('文件未上传或内容为空');
            }
            const fileContent = fs.readFileSync(file.data, 'utf-8');
            const { currentPath, date_dir, date_time } = this.generatePathFromCurrentTime();
            const base_url = `D:/01北京城市内涝模型/6_全国降雨数据/${currentPath}/01_origin`; // 目标目录
            const params_url = `D:/01北京城市内涝模型/6_全国降雨数据/${currentPath}/02_params`; // 目标目录
            const output_url = `D:/01北京城市内涝模型/6_全国降雨数据/${currentPath}/04_result`; // 目标目录
            // 检查文件夹是否存在
            if (!fs.existsSync(base_url)) {
                // 创建文件夹
                fs.mkdirSync(base_url, { recursive: true });
            }

            if (!fs.existsSync(params_url)) {
                // 创建文件夹
                fs.mkdirSync(params_url, { recursive: true });
            }

            const filename = file.filename; // 从上传信息中获取文件名
            const uploadPath = path.join(base_url, filename); // 拼接完整路径
            const params_path = path.join(params_url, "input.json")
            const outputFile = path.join(output_url, "output.json")
            // 保存文件
            await fs1.writeFile(uploadPath, fileContent);
            const fileNameWithoutExtension = path.parse(uploadPath).name;
            let inputParams = {
                taskId: params.taskId,
                forecastpTimestamp: this.generateUTCFromInputTime(params.resultTimestamp),
                resultTimestamp: this.generateUTCFromInputTime(params.resultTimestamp),
                forecastRange: params.forecastRange,
                cyRainURL: params_path,
                date_dir: date_dir,
                date_time: date_time,
                file_name: fileNameWithoutExtension,
                output_file: outputFile
            };
            // 将 JSON 字符串写入指定路径的文件
            await fs.promises.writeFile(params_path, JSON.stringify(inputParams), 'utf8');

            this.pushQuanguoPreviewData(params_path)

             // 设置要保存的文件目录路径
             const targetDir = path.join('D:/02ChinaModel/03Warning/', params.taskId, '02_RainFall');

             // 如果目录不存在，则创建目录
             if (!fs.existsSync(targetDir)) {
                 fs.mkdirSync(targetDir, { recursive: true });
             }

            const copyFilePath = path.join(targetDir, 'RAIN_FALL.asc');
            fs.writeFileSync(copyFilePath, fileContent);

            // 保存 params 到 01_params/input.json
            const paramsDir = path.join('D:/02ChinaModel/03Warning/', params.taskId, '01_origin');

            // 如果 01_params 目录不存在，创建该目录
            if (!fs.existsSync(paramsDir)) {
                fs.mkdirSync(paramsDir, { recursive: true });
            }

            // 定义 input.json 的完整路径
            const paramsFilePath = path.join(paramsDir, 'input_China.json');

            // 将 params 对象转换为 JSON 并写入文件
            fs.writeFileSync(paramsFilePath, JSON.stringify(params, null, 2), 'utf-8');
            this.graphService.executeGraphByDynamic4(81, params.taskId)
            return result;
        } catch (error) {
            console.log(error)
            console.error('上传失败:', error.message.cause);
            return {
                success: false,
                message: '参数验证失败或文件上传失败',
                error: error.message.cause,
            };
        }
    }

    @Validate()
    async uploadFile2(params: uploadDto, file: any) {
        try {
            // 定义初始返回结果
            let result = {
                success: true,
                taskId: params.taskId,
                message: '上传成功',
            };

            // 检查文件是否存在
            if (!file || (!file.data && !file.buffer)) {
                throw new Error('文件未上传或内容为空');
            }

            // 设置要保存的文件目录路径
            const targetDir = path.join('D:/02ChinaModel/03Warning/', params.taskId, '02_RainFall');

            // 如果目录不存在，则创建目录
            if (!fs.existsSync(targetDir)) {
                fs.mkdirSync(targetDir, { recursive: true });
            }

            // 定义文件保存的完整路径
            const targetFilePath = path.join(targetDir, file.filename);

            // 根据 file 类型读取内容
            const fileContent = file.buffer
                ? file.buffer.toString('utf-8')
                : fs.readFileSync(file.data, 'utf-8');

            // 将文件内容写入目标文件
            fs.writeFileSync(targetFilePath, fileContent);

            // 在当前目录下复制一份文件并命名为 RAIN_FALL.asc
            const copyFilePath = path.join(targetDir, 'RAIN_FALL.asc');
            fs.writeFileSync(copyFilePath, fileContent);

            // 保存 params 到 01_params/input.json
            const paramsDir = path.join('D:/02ChinaModel/03Warning/', params.taskId, '01_origin');

            // 如果 01_params 目录不存在，创建该目录
            if (!fs.existsSync(paramsDir)) {
                fs.mkdirSync(paramsDir, { recursive: true });
            }

            // 定义 input.json 的完整路径
            const paramsFilePath = path.join(paramsDir, 'input_China.json');

            // 将 params 对象转换为 JSON 并写入文件
            fs.writeFileSync(paramsFilePath, JSON.stringify(params, null, 2), 'utf-8');
            this.graphService.executeGraphByDynamic4(81, params.taskId)
            return result;
        } catch (error) {
            console.error('上传失败:', error.message);
            return {
                success: false,
                message: '参数验证失败或文件上传失败',
                error: error.message,
            };
        }
    }

    generateUTCFromInputTime(inputTime) {
        const inputDate = new Date(inputTime);
        const utcYear = inputDate.getUTCFullYear();
        const utcMonth = String(inputDate.getUTCMonth() + 1).padStart(2, '0');
        const utcDay = String(inputDate.getUTCDate()).padStart(2, '0');
        const utcHours = String(inputDate.getUTCHours()).padStart(2, '0');
        const utcMinutes = String(inputDate.getUTCMinutes()).padStart(2, '0');
        const utcSeconds = String(inputDate.getUTCSeconds()).padStart(2, '0');

        const utcTimeString = `${utcYear}-${utcMonth}-${utcDay}T${utcHours}:${utcMinutes}:${utcSeconds}.000Z`;

        return utcTimeString;
    }

    generatePathFromCurrentTime() {
        const currentDateTime = new Date();
        const year = currentDateTime.getFullYear();
        const month = String(currentDateTime.getMonth() + 1).padStart(2, '0');
        const day = String(currentDateTime.getDate()).padStart(2, '0');
        const hours = String(currentDateTime.getHours()).padStart(2, '0');
        const minutes = String(currentDateTime.getMinutes()).padStart(2, '0');
        const seconds = String(currentDateTime.getSeconds()).padStart(2, '0');

        const currentPath = `${year}/${year}-${month}-${day}/${year}${month}${day}${hours}${minutes}${seconds}`;
        const date_dir = `${year}/${year}-${month}-${day}`
        const date_time = `${year}${month}${day}${hours}${minutes}${seconds}`

        return { currentPath, date_dir, date_time };
    }





    async downloadRainfallData() {
        const url = 'https://wrapper.cyapi.cn/v1/radar/cndata/forecastp?token=DUqHV6RCwVCAm2mB&province_id=11';
        try {
            // 获取数据
            const response = await axios.get(url);
            const data = response.data;

            // 提取 datetime 和 data_url
            const datetime = data.cndata[0].datetime;
            const dataUrls = data.cndata[0].data_url;

            // 格式化 datetime
            const year = datetime.split('-')[0];
            const date = datetime.split('T')[0]; // 2024-09-04
            const formattedTime = datetime.replace(/[-:T]/g, ''); // 202409041030
            const date_dir = `${year}/${date}`;
            // 设置文件夹根路径
            const baseDir = path.join(
                'D:',
                '01北京城市内涝模型',
                '5_降水数据下载',
                '01_降水数据',
                year,
                date,
                formattedTime
            );

            // 检查文件夹是否存在
            if (!fs.existsSync(baseDir)) {
                // 创建文件夹
                fs.mkdirSync(baseDir, { recursive: true });
            }
            // 下载文件并保存
            for (const url of dataUrls) {
                // 移除不允许的字符
                const sanitizedUrl = url.split('?')[0]; // 仅保留文件名部分
                const fileName = path.basename(sanitizedUrl); // 提取文件名
                const filePath = path.join(baseDir, fileName); // 构建完整路径
                const writer = fs.createWriteStream(filePath);
                const response = await axios.get(url, { responseType: 'stream' });
                response.data.pipe(writer);

                // 等待文件写入完成
                await new Promise((resolve, reject) => {
                    writer.on('finish', resolve);
                    writer.on('error', reject);
                });
            }
            console.log('预测降雨数据下载完成');
            this.downloadHistoryData(datetime, date_dir, formattedTime)
        } catch (error) {
            console.error('Error fetching data:', error);
            throw new Error('Failed to download rainfall data');
        }
    }

    async downloadHistoryData(forecastpTimestamp, date_dir, date_time) {
        const url = 'http://api.caiyunapp.com/v1/historical_precipitation?token=DUqHV6RCwVCAm2mB&product=grid';
        try {
            // 获取数据
            const response = await axios.get(url);
            const data = response.data;

            // 提取 datetime 和 data_url
            const images = data.images;
            const resultTimestamp = new Date(
                images[images.length - 1][2] * 1000
            ).toISOString();
            // 下载文件并保存
            for (const image of images) {
                const datetime = new Date(image[2] * 1000).toISOString();
                // 格式化 datetime
                const year = datetime.split('-')[0];
                const date = datetime.split('T')[0]; // 2024-09-04
                // 设置文件夹根路径
                const baseDir = path.join('D:', '01北京城市内涝模型', '5_降水数据下载', '01_降水数据', year, date);
                // 检查文件夹是否存在
                if (!fs.existsSync(baseDir)) {
                    // 创建文件夹
                    fs.mkdirSync(baseDir, { recursive: true });
                }
                const gridResponse = await axios.get(image[0], { responseType: 'arraybuffer' });

                // 清理文件名，去除查询参数
                const gridName = path.basename(image[0].split('?')[0]); // 获取没有查询参数的文件名
                const gridPath = path.join(baseDir, gridName);
                fs.writeFileSync(gridPath, gridResponse.data);

                const imageResponse = await axios.get(image[1], { responseType: 'arraybuffer' });
                const imageName = path.basename(image[1].split('?')[0]); // 获取没有查询参数的文件名
                const imagePath = path.join(baseDir, imageName);
                fs.writeFileSync(imagePath, imageResponse.data);
            }

            const lastGridName = path.basename(images[images.length - 1][0].split('?')[0]).replace('.npz', '');
            let input = {
                taskId: uuidv4(),
                forecastpTimestamp: forecastpTimestamp,
                resultTimestamp: resultTimestamp,
                forecastRange: 2,
                cyRainURL: 'D:/01北京城市内涝模型/5_降水数据下载/01_降水数据/input.json',
                history_file: lastGridName,
                date_dir: date_dir,
                date_time: date_time,
            };
            await fs1.writeFile(input.cyRainURL, JSON.stringify(input));
            console.log('历史数据（image和grid）下载完成');
        } catch (error) {
            console.error('Error fetching data:', error);
            throw new Error('Failed to download rainfall data');
        }
    }


    async pushPreviewData() {
        const datetime = new Date()
        const year = datetime.getFullYear().toString();
        const month = (datetime.getMonth() + 1).toString().padStart(2, '0');
        const day = datetime.getDate().toString().padStart(2, '0');
        const baseDir = "D:/01北京城市内涝模型/5_降水数据下载/01_降水数据/result/" + year + '/' + `${year}-${month}-${day}`
        if (!fs.existsSync(baseDir)) {
            // 创建文件夹
            fs.mkdirSync(baseDir, { recursive: true });
        }
        const fileName = "output_" + datetime.getTime() + '.json'
        const outputFile = path.join(baseDir, fileName);
        const TaskID = uuidv4()
        const algorithm = await this.AlgorithmModel.findOne({
            where: { id: 136 },
        });

        if (!algorithm) {
            return {
                success: false,
                message: '未找到要执行的算法',
            };
        }
        const parsedParameters = JSON.parse(algorithm.parameters);
        try {
            parsedParameters.forEach(param => {
                const key = param.param_name;
                if (key == 'TaskID') {
                    param.default_value = TaskID;
                }
                if (key == 'outputFile') {
                    param.default_value = outputFile;
                }
            });
            algorithm.parameters = JSON.stringify(parsedParameters);
            const task = await this.taskService.createTask(algorithm);
            return {
                success: true,
                data: {
                    id: task.id,
                    taskId: TaskID,
                },
                message: '任务创建成功',
            };
        } catch (error) {
            console.error('创建任务失败:', error.message.cause);
            return {
                success: false,
                message: '参数验证失败或创建任务失败',
                error: error.message.cause,
            };

            // wait fs1.writeFile(input.cyRainURL, JSON.stringify(input));
        }
    }

    async pushPreviewData2() {
        const inputFile = 'D:/01北京城市内涝模型/5_降水数据下载/01_降水数据/input.json'
        const data = await fs1.readFile(inputFile, 'utf-8');
        const jsonData = JSON.parse(data);
        console.log(jsonData)
        this.graphService.executeGraphByDynamic(76, jsonData)
    }

    async pushQuanguoPreviewData(inputFile) {
        const data = await fs1.readFile(inputFile, 'utf-8');
        const jsonData = JSON.parse(data);
        console.log(jsonData)
        this.graphService.executeGraphByDynamic2(77, jsonData)
    }
}
